<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <!-- 
      防抖与节流
        为什么需要防抖和节流
          在一些二高频率事件触发的场景下我们不希望对应的事件处理函数多次执行

        场景
          滚动事件
          输入的模糊匹配
          轮播图切换
          点击操作
          ...
        
        浏览器默认情况下都会有自己的监听事件间隔（4-6ms）,如果检测到多次事件的监听执行,那么就会造成不必要的资源浪费

        前置的场景：界面上有一个按钮,我们可以连续多次点击

        防抖：
          对于这个高频的炒操作来说,我们只希望识别一次点击,可以认为或者是最后一次

        节流：
          对于高频操作,我们可以自己来设置频率,让本来会执行很多次的事件触发,按照我们定义的频率减少触发的次数
    -->

    <button id="btn">点击</button>
    <script>
      var btnEl = document.getElementById("btn");

      // 防抖
      function myDebounce(handle, wait, immediate) {
        // 参数判断,默认值处理
        if (typeof handle !== "function")
          throw new Error("handle must be a function");
        if (typeof wait === "undefined") wait = 300;
        // wait 没穿数字但是穿了boolean值
        if (typeof wait === "boolean") {
          immediate = wait;
          wait = 300;
        }
        if (typeof immediate !== "boolean") immediate = false;

        let timer = null;
        return function proxy(...args) {
          let self = this;
          init = immediate && !timer;
          // 重复点击取消上一次点击
          timer && clearTimeout(timer);
          timer = setTimeout(() => {
            // timer重置, 避免wait时间结束后再次点击后不触发init后的函数执行
            timer = null;
            // 定时器中的代码只有immediate为false才会执行
            !immediate ? handle.call(self, ...args) : null;
          }, wait);

          // 立即执行(使用timer作为判断条件,并且先执行init后面的函数调用在执行timer定时器代码,此时timer为null,
          // 后续在wait时间点击,init始终有值,因此只能执行一次,只有到wait时间结束后,init才会重置为true)
          init ? handle.call(self, ...args) : null;
        };
      }

      function btnClick() {
        console.log("点击了");
      }

      btnEl.onclick = myDebounce(btnClick, 200, false);
    </script>
  </body>
</html>
